﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading;
using FA.Library.Plugin;
using FA.Plugins.GUIPlugin;
using FA.Plugins.GUIPlugin.View;
using FA.Library.Sim.Events;
using FA.Library.ExtensionMethods;
using System.Windows.Threading;
using FA.Library.Sim;
using FA.Library.Sim.Aircraft;

namespace FA.Plugins.GUIPlugin.Plugin
{
    public class GUIPlugin : IPlugin
    {
        public event EventHandler Disposed;
        public event EventHandler OnPluginStartEvent;
        public event EventHandler OnPluginStopEvent;
        public event EventHandler OnPluginSettingsChangedEvent;
        public event SimMessageEvent OnSimMessageEvent;
        public event SimExceptionEvent OnSimExceptionEvent;
        public event SimAircraftModelChangedEvent OnSimAircraftModelChangedEvent;
        
        public string Name { get; set; }

        public AircraftModel AircraftModel
        {
            get
            {
                AircraftModel model = null;
                if (_mainWindow != null && _mainWindow.ViewModel.Aircraft != null)
                    model = (AircraftModel)_mainWindow.ViewModel.Aircraft.Clone();
                return model;
            }
        }

        public bool IsRunning
        {
            get { return _isRunning; }
            private set
            {
                if (_isRunning != value)
                {
                    _isRunning = value;

                    if (_isRunning && OnPluginStartEvent != null)
                        OnPluginStartEvent(this, null);
                    else if (!_isRunning && OnPluginStopEvent != null)
                        OnPluginStopEvent(this, null);
                }
            }
        }
        private bool _isRunning;

        public bool IsDisposed { get; private set; }

        private Dictionary<string, string> _settings = new Dictionary<string, string>();
        private MainWindow _mainWindow;
        private Thread _thread;
        private Dispatcher _uiDispatcher;

        public GUIPlugin()
        {
            IsRunning = false;
            IsDisposed = false;
        }

        /// <summary>
        /// Initialise the plugin.
        /// </summary>
        /// <param name="host"></param>
        public void Initialise()
        {
        }
        
        /// <summary>
        /// Run the plugin.
        /// </summary>
        public void Start()
        {
            // Create the thread in which the UI will run
            _thread = new Thread(() =>
            {
                // Create UI application
                _mainWindow = new MainWindow();
                _uiDispatcher = _mainWindow.Dispatcher;

                // The thread will close when the main window is closed
                _mainWindow.Closed += (sender, e) => Stop();

                // Propogate aircraft model change events
                _mainWindow.ViewModel.OnSimAircraftModelChangedEvent += (sender, args) =>
                    {
                        if (OnSimAircraftModelChangedEvent != null)
                            OnSimAircraftModelChangedEvent(this, args);
                    };

                // Show the window
                _mainWindow.Show();

                Dispatcher.Run();
            });
            _thread.SetApartmentState(ApartmentState.STA);

            // Run the thread
            _thread.Start();

            IsRunning = true;
        }

        /// <summary>
        /// Stop the plugin.
        /// </summary>
        public void Stop()
        {
            // Shut down the UI thread
            if (_uiDispatcher != null)
                _uiDispatcher.InvokeShutdown();

            // Wait for the thread to end
            if (_thread != null && _thread != Thread.CurrentThread)
                _thread.Join();

            IsRunning = false;
        }

        public void UpdateSettings(Dictionary<string, string> settings)
        {
            if (settings == null)
                settings = new Dictionary<string, string>();

            if (!_settings.CheckForEquality<string, string>(settings))
            {
                _settings = settings;

                if (OnPluginSettingsChangedEvent != null)
                    OnPluginSettingsChangedEvent(this, null);
            }
        }

        public Dictionary<string, string> GetSettings()
        {
            // Clone the dictionary
            return _settings.ToDictionary(entry => entry.Key, entry => entry.Value);
        }

        /// <summary>
        /// Update the aircraft model for the plugin.
        /// </summary>
        /// <param name="model"></param>
        public void UpdateAircraftModel(AircraftModel model, bool supressEvent)
        {
            if (_mainWindow != null)
                _mainWindow.ViewModel.UpdateAircraftModel(model, supressEvent);
        }

        /// <summary>
        /// Dispose the plugin.
        /// </summary>
        public void Dispose()
        {
            if (IsDisposed)
                return;

            Stop();

            IsRunning = false;
            IsDisposed = true;

            if (Disposed != null)
                Disposed(this, null);
        }
    }
}